<html>
  <head>
	  <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <title>i5ting_ztree_toc:nodejs</title>
		<link href="toc/style/github-bf51422f4bb36427d391e4b75a1daa083c2d840e.css" media="all" rel="stylesheet" type="text/css"/>
		<link href="toc/style/github2-d731afd4f624c99a4b19ad69f3083cd6d02b81d5.css" media="all" rel="stylesheet" type="text/css"/>
		<link href="toc/css/zTreeStyle/zTreeStyle.css" media="all" rel="stylesheet" type="text/css"/>
	  <style>
		pre {
		    counter-reset: line-numbering;
		    border: solid 1px #d9d9d9;
		    border-radius: 0;
		    background: #fff;
		    padding: 0;
		    line-height: 23px;
		    margin-bottom: 30px;
		    white-space: pre;
		    overflow-x: auto;
		    word-break: inherit;
		    word-wrap: inherit;
		}

		pre a::before {
		  content: counter(line-numbering);
		  counter-increment: line-numbering;
		  padding-right: 1em; /* space after numbers */
		  width: 25px;
		  text-align: right;
		  opacity: 0.7;
		  display: inline-block;
		  color: #aaa;
		  background: #eee;
		  margin-right: 16px;
		  padding: 2px 10px;
		  font-size: 13px;
		  -webkit-touch-callout: none;
		  -webkit-user-select: none;
		  -khtml-user-select: none;
		  -moz-user-select: none;
		  -ms-user-select: none;
		  user-select: none;
		}

		pre a:first-of-type::before {
		  padding-top: 10px;
		}

		pre a:last-of-type::before {
		  padding-bottom: 10px;
		}

		pre a:only-of-type::before {
		  padding: 10px;
		}

		.highlight { background-color: #ffffcc } /* RIGHT */
		</style>
  </head>
  <body>
	  <div>
				<div style='width:25%;'>
						<ul id="tree" class="ztree" style='width:100%'>

						</ul>
				</div>
        <div id='readme' style='width:70%;margin-left:20%;'>
          	<article class='markdown-body'>
            	<h1 id="node-js-">node.js学习</h1>
<h2 id="node-js-">node.js 是什么</h2>
<p>node.js是一款基于Chrome V8内核的javaScript运行环境</p>
<h2 id="-">下载与安装</h2>
<p>官网下载，傻瓜式安装</p>
<h2 id="-">使用</h2>
<p>命令行使用</p>
<h2 id="fs-const-fs-require-fs-">fs文件系统模块  const fs = require(&#39;fs&#39;);</h2>
<h3 id="-">定义</h3>
<p>fs模块是Node.js官方提供的，用来操作文件的模块，它提供了一系列的方法和属性，用来满足用户对文件的操作需求
例如</p>
<ul>
<li>fs.readFile()方法，用来读取指定文件中的内容</li>
<li>fs.writeFile()方法，用来向指定的文件中写入内容</li>
</ul>
<p>注意：使用该模块需要先导入</p>
<h3 id="-fs-readfile-">读取指定文件中的内容 fs.readFile() 方法</h3>
<p>格式：fs.readFile(path[,CharSet],callback);</p>
<h3 id="-">向指定文件中写入内容</h3>
<p>格式：fs.writeFile(file,data[,option],callback)</p>
<ul>
<li>file ==&gt;文件路径字符串</li>
<li>data ==&gt; 表示要写入的内容</li>
<li>option ==&gt; 写入格式 默认utf8</li>
<li>callback ==&gt; 回调函数</li>
</ul>
<h2 id="-">处理路径问题</h2>
<h3 id="-">路径拼接错误</h3>
<p>因为终端的执行路径，导致动态拼接的路劲为错误路径
解放方案：</p>
<ul>
<li>1.提供绝对路径</li>
<li>2.__dirname 表示当前目录</li>
</ul>
<h2 id="path-const-path-require-path-">path路径模块 const path = require(&#39;path&#39;);</h2>
<h3 id="-">常用方法</h3>
<ul>
<li>path.join() 将多个路径片段拼接成一个完整的路径字符串 </li>
<li>path.basename() 在路径字符串中将文件名解析出来  可以传递第二个参数，用于删除末尾的字符串<pre><code class="lang-js">path.basename(&#39;\\a\\b\\c\\index.html&#39;,&#39;html&#39;)   //&lt;==这个结果是index
</code></pre>
--path.extname 获取文件扩展名</li>
</ul>
<h2 id="http-">http模块</h2>
<p>http模块是node.js官方提供的用来创建服务器的模块.通过http模块提供的http.createServer()方法，就能很方便的把一台普通的电脑,变成一台Web服务器，从而对外提供Web 资源服务</p>
<ul>
<li>需要导入http模块</li>
<li>const http = require(&#39;http);</li>
</ul>
<h3 id="-">服务器以及相关概念</h3>
<h4 id="ip-">IP地址</h4>
<p>每台计算机的唯一表示
采用点分十进制表示(a,b,c,d)</p>
<h4 id="-domain-name-">域名(Domain Name)和域名服务器</h4>
<h4 id="-">端口号</h4>
<p>每个web服务都对应唯一的一个端口号，通过这玩意准确识别</p>
<h3 id="-">创建一个服务器的步骤</h3>
<pre><code class="lang-js">//导入模块
const http = require(&#39;http&#39;);
//创建服务
const server = http.crearServer();
//为服务器绑定请求事件
server.on(&#39;request&#39;,(req,res)=&gt;{});
//启动服务器
server.listen(80,()=&gt;{
    console.log(&#39;port 80 running...&#39;)
})

</code></pre>
<h3 id="req-">req 请求对象</h3>
<ul>
<li>url:地址</li>
<li>method:请求类型</li>
<li></li>
</ul>
<h3 id="res-">res 响应对象</h3>
<ul>
<li>end(data):向服务器发送数据并结束本次请求</li>
</ul>
<h2 id="-">模块化</h2>
<p>遵守对应的规则，把一个大文件拆分成独立并互相依赖的小模块</p>
<h3 id="-">分类</h3>
<ol>
<li>自定义模块</li>
<li>官方模块</li>
<li>第三方模块</li>
</ol>
<h3 id="-">加载</h3>
<h4 id="require-">require方法</h4>
<p>加载模块时，会执行模块中的代码</p>
<h3 id="-">作用域</h3>
<p>在模块内定义的成员无法被模块外访问</p>
<h2 id="module-exports-">module.exports 对象</h2>
<p>在自定义模块中可以使用module.exports对象，将模块中的成员共享出去，供外界使用,外界用require方法导入自定义模块时，得到的就是module.exports所指向的对象</p>
<h3 id="-">共享成员时的注意点</h3>
<p>s使用require()当打导入模块时，导入的结果永远以module,exports指向的对象为准</p>
<h3 id="exports-">exports对象</h3>
<p>由于module.exports单词写起来比较复杂,为了简化共享成员的代码,Node提供了exports对象。默认情况下，exports和module.exports都指向同一个对象，最终的结果，以module.export指向的对象为准</p>
<h3 id="node-js-">node.js中的模块规范</h3>
<p>Node.js遵循了CommonJS模块化规范，CommonJs中规定了模块的特性，和各模块之间如何相互依赖  </p>
<h4 id="commonjs-">CommonJs规定</h4>
<ol>
<li>每个模块内部，module变量代表当前模块</li>
<li>module变量是一个对象,它的export属性(即module.exports)是对外的接口</li>
<li>加载某个模块其实就是加载这个模块的module.export属性,require()方法用于加载模块</li>
</ol>
<h2 id="npm-">NPM与包</h2>
<h3 id="what-is-">what is 包</h3>
<p>就是第三方模块，叫法不同而已</p>
<h3 id="-">包的来源</h3>
<p>由第三方开发，免费下载使用</p>
<h3 id="why-need-">why need 包</h3>
<p>由于Node.js的内置模块仅仅提供了一些底层的API，导致在基于内置模块进行项目开发的时候，效率很低，包是基于内置模块封装出来的,提供了更高级，更方便的API，极大的提高了开发效率,包和浏览器之间的关系，就类似于Jquery和浏览器内置Api之间的关系</p>
<h3 id="-">从哪里下载包</h3>
<ul>
<li><a href="https://npmjs.com">https://npmjs.com</a> 全球最大包共享网站</li>
<li><a href="https://registry.npmjs.org">https://registry.npmjs.org</a> 专门下载包的服务器</li>
</ul>
<h3 id="-">如何下载</h3>
<p>npm(node package manage)包管理工具 
npm install 完整的包名称
npm i 完整的包名称</p>
<h3 id="-">注意点</h3>
<ol>
<li><p>初次装包完成后，在项目文件夹下多一个叫做node_modules的文件夹和package-lock.json的配置文件,其中nodel_modules文件夹用来存放所有已安装到项目中的包。require()导入第三方包时，就是从这个目录中查找并加载包<br>package-lock.json配置文件用来记录node_modules目录下的每一个包的下载信息,例如包的版本号，下载地址等</p>
</li>
<li><p>安装指定版本的包
默认情况下，会自动安装最新版本的包,如果需要安装指定版本的包,可以在包名后面加上@符号指定需要的版本<br>例：  </p>
<pre><code>npm i moment@2.22.2
</code></pre></li>
<li><p>包的语义化版本规范<br>包的版本号是以“点分十进制”定义的，总共有三位数字  </p>
</li>
<li>第一位：大版本</li>
<li>第二位：功能版本</li>
<li>第三位： bug修复版本</li>
</ol>
<h3 id="-">包管理配置文件</h3>
<ol>
<li>多人协作的问题：第三方的包体积过大，不方便成员之间共享项目源代码<br>解决方案：共享时剔除node_modules</li>
<li>在项目根目录中，创建一个叫做package.json的配置文件,即可用来记录在项目中安装了哪些包，从而方便剔除node_modules目录之后，在团队成员之间共享项目的源代码  </li>
<li>npm包管理工具提供了一个快捷命令，可以在执行命令时所处的目录中快速创建package.json这个包管理配置文件<pre><code>npm init -y
</code></pre>上述命令只能在英文的目录下运行成功，所以项目文件夹的名称一定要使用英文</li>
</ol>
<h4 id="dependencies-">dependencies节点</h4>
<p>dependencies节点专门用来记录安装了哪些包 </p>
<h3 id="-package-json-dependencies-">一次性安装package.json中dependencies记录的所有包</h3>
<pre><code>npm i
</code></pre><h3 id="-">卸载包</h3>
<ul>
<li>uninstall 包名</li>
</ul>
<h3 id="devdependencies-">devDependencies 节点</h3>
<p>如果某些包只在项目开发阶段会用到，在项目上线以后就不会用到，则可以放到这个包中</p>
<pre><code>//安装指定的包，并记录到devDependencies节点中
npm i 包名 -D
//注意：上述命令只是简写形式，等价与下面完整的写法
nom install 包名 --save-dev
</code></pre><h3 id="-">解决包下载速度过慢的问题</h3>
<pre><code>//查询当前的下载路径
npm config get registry
//修改当前的下载路径
npm config set registry = 下载路径 &#39;淘宝：https://registry.npm.taobao.org&#39;
</code></pre><h4 id="nrm-">nrm管理镜像源</h4>
<pre><code>//安装 -g表示全局可用
npm i nrm -g
//查看所有可用的镜像源
npm ls
</code></pre><h3 id="-">包的分类</h3>
<h4 id="-">项目包</h4>
<ol>
<li>开发依赖包（被记录到devDependencies节点的包，只在开发时候使用）<pre><code>npm install packageName --save-dev
</code></pre></li>
<li>核心依赖包（被记录到dependencies节点中的包，开发上线都用）<pre><code>npm i packageName
</code></pre></li>
</ol>
<h4 id="-">全局包</h4>
<h3 id="-">规范的包结构</h3>
<ol>
<li>包必须以单独的目录存在</li>
<li>包的顶级目录要包含package.json这个包管理配置文件</li>
<li>package.json中必须包含name,version,main这三个属性，分别表示包的名字，版本号和入口  </li>
</ol>
<p>/<em> 在导入一个包时，会首先执行main指向的对象</em>/</p>
<h3 id="-">开发属于自己的包</h3>
<h4 id="-">初始化包结构</h4>
<ol>
<li>新建包文件夹，作为包的根目录</li>
<li><p>在包根目录中，创建如下三个文件。</p>
<ul>
<li>package.json 包管理配置文件</li>
<li>index.js 包的入口文件</li>
<li>README.md 包的说明文档</li>
</ul>
<h4 id="package-js-">package.js的五个必要属性</h4>
<pre><code class="lang-js">{
 &quot;name&quot;:&quot;zengzeng&quot;,  //包的名称
 &quot;version&quot;:&quot;1.0.0&quot;,  //包的版本号
 &quot;main&quot;:&quot;index.js&quot;,   //包的入口
 &quot;description&quot;:&quot;这是一个测试用包&quot;, //包的描述信息
 &quot;keywords&quot;:[&quot;zeng&quot;,&quot;pro&quot;],  //搜索关键字
 &quot;license&quot;:&quot;ISC&quot;     //开源许可协议

}
</code></pre>
<ul>
<li>展开预算符 ... 将对象中的属性全部展开</li>
</ul>
<h4 id="-">包的发布</h4>
<pre><code>//进入包的根目录
npm publish //发布包
npm unpublish  //只能删除72小时以内发布的包
//并且24小时以内不允许发布相同名字的包

</code></pre><h3 id="-">模块的加载机制</h3>
<p>模块在第一次加载后会被缓存，也就是说，即使多次require模块，也不会导致模块中的代码反复执行</p>
<ul>
<li>内置模块加载优先级最高</li>
</ul>
<h3 id="-">自定义模块的加载机制</h3>
<p>使用require加载自定义模块时，必须指定./或者../开头，否则会被当做内置模块或者第三方模块进行加载  </p>
<p>引入自定义模块若忽略扩展名会自动补全以下扩展</p>
<ol>
<li>确切文件名</li>
<li>.js</li>
<li>.json</li>
<li>.node</li>
<li>找不到，报错</li>
</ol>
</li>
</ol>
<h3 id="-">第三方模块的加载机制</h3>
<p>在加载一个第三方模块时。node会先找寻父级目录下的node_modules中查找，如果没有则会在父级的父级目录下的node_modules中查找，以此类推，一直找到盘符的根，如果还没有则报错</p>
<h3 id="-">目录作为模块的加载机制</h3>
<p>当把模块作为模块标识符，传递给require()进行加载的时候有三种加载方式</p>
<ol>
<li>在被加载的目录下面查找一个叫做package.json的文件,并寻找main属性作为入口</li>
<li>找寻目录下的index.js文件</li>
<li>上二者皆不成功则报错</li>
</ol>
<h2 id="express-">express的基本使用</h2>
<h3 id="-">参数的获取</h3>
<pre><code class="lang-js">req.query 这个属性包含get请求中的所有参数
req.param 这个属性可以动态获取链接中的值
//注意 路由格式(&#39;/acb/:d&#39;) :后表示动态参数
</code></pre>
<h3 id="-">静态资源托管</h3>
<p>express.static(&#39;要托管的文件夹&#39;)<br>一般写法
app.use(express.static(&#39;要托管的文件夹&#39;))
挂载路径前缀
app.use(&#39;前缀&#39;,express.static(&#39;要托管的文件夹&#39;))  </p>
<p><strong>app.use()这个方法常用于注册全局中间件</strong></p>
<h3 id="nodemon-">nodemon插件</h3>
<p>nodemon 命令启动项目实现热重载</p>
<h3 id="-">路由</h3>
<p>每当一个请求到达服务器之后，<strong>需要先经过路由的匹配</strong>，只有匹配成功之后，才会调用对应的而处理函数，在匹配时，会按照路由的顺序进行匹配，如果<strong>请求类型</strong>和<strong>请求的URL</strong>同事匹配成功，则Express会将注册请求交给对应的function进行处理
<img src="http://qi.zengzeng.pro/vscode/20230222151915.png" alt="路由的概念"></p>
<h4 id="-">模块化路由</h4>
<p>为了<strong>方便对路由进行模块化的管理</strong>，express不建议将路由直接挂载到app上，应当抽离出来作为单独的文件存在  </p>
<ol>
<li>创建路由模块对应的.js文件</li>
<li>调用express.Router()函数创建路由对象</li>
<li>向路由对象上挂载具体的路由</li>
<li>使用module.exports向外共享路由对象</li>
<li>使用app.use()注册路由</li>
</ol>
<h2 id="-">中间件</h2>
<h3 id="-">中间件的格式</h3>
<p>express的中间件本质上就是一个function处理函数  </p>
<p><img src="http://qi.zengzeng.pro/vscode/20230222155408.png" alt="官方截图"></p>
<p><strong>注意：中间件的形参列表中，<em>必须包含next参数</em>。而路由的处理函数只包含req和res参数。</strong></p>
<h3 id="next-">next函数的作用</h3>
<p>next函数是实现多个中间件连续调用的关键，它表示把流转关系交给下一个中间件或路由  </p>
<h3 id="-">中间件的作用</h3>
<p>多个中间件之间，他们的req和res参数都是相同的，所以上游可以在这两个对象上挂载参数供下游的中间件使用</p>
<pre><code class="lang-js">app.get(&quot;/&quot;,(req,res,next)=&gt;{
    req.a = &quot;hello&quot;
})
app.get(&quot;/&quot;,(req,res,next)=&gt;{
    console.log(req.a)      //此时就会得到hello
})
</code></pre>
<p><strong>中间件有req，res，next三个参数组成</strong></p>
<h3 id="-">中间件的注意事项</h3>
<ol>
<li>一定要在<strong>路由之前</strong>注册中间件</li>
<li>客户端发送过来的请求，<em>**可以连续调用多个</em>中间件进行处理</li>
<li>执行完毕中间件的逻辑之后要记得调用next()函数</li>
<li>在执行next()不要进行其他的操作</li>
<li>req和res在多个中间件之间是共享的</li>
</ol>
<h3 id="-">中间件的分类</h3>
<ol>
<li>应用级别
通过app.use()或app.get()或app.post()绑定的中间件</li>
<li>路由级别
绑定到Route上的中间件</li>
<li>错误级别
捕获并处理全局的异常，这个级别的中间件有四个形参(err,req,res,next)</li>
<li>Express内置<ol>
<li><strong>express.static</strong> 用于快速托管静态资源的内置中间件。</li>
<li><strong>express.json</strong> 用于解析JSON格式的请求体数据</li>
<li><strong>express.urlencoded</strong>用于解析URL-encoded格式的请求体数据 需要加上配置参数对象<pre><code class="lang-js">//通过use对中间件进行配置
app.use(express.json())
app.use(express.urlencoded({extended:false}))
</code></pre>
</li>
</ol>
</li>
<li>第三方
由第三方开发的中间件，例如body-parser</li>
</ol>
<h3 id="-post-">自制解析post请求的中间件</h3>
<pre><code class="lang-js">//制作一个全局中间件放到最前面
app.use((req,res,next)=&gt;{
    //定义数据字符串
    let str = &#39;&#39;;
    //通过监听req的data时间来接收数据
    req.on(&#39;data&#39;,e=&gt;str+=e);
    //通过监听req的end时间来确认数据接收完毕
    req.on(&#39;end&#39;,()=&gt;{
        //调用内置模块的qureystring.parse方法将字符串转化为实体对象并赋值给req.body
        req.body = querystring.parse(str);
        //将权限转交出去
        next()

    })
})
</code></pre>
<h3 id="-">跨域问题</h3>
<p>CORS(Cross-Origin Resource Sharing,跨域资源共享)由一系列的<strong>http响应头</strong>组成，<strong>这些http响应头决定浏览器是否阻止前端js代码跨域获取资源。</strong>  </p>
<p>浏览器的<strong>同源安全策略</strong>默认会阻止网页“跨域”获取资源 。但如果接口服务器配置了CORS相关的http响应头就可以接触浏览器短的跨域访问限制  </p>
<p><img src="http://qi.zengzeng.pro/vscode/20230222202923.png" alt="跨域问题">  </p>
<h4 id="-">注意</h4>
<ol>
<li>cors主要在<strong>服务器端</strong>进行配置。客户端浏览器<strong>无需做任何额外的配置</strong>，即可请求开启了cors的接口</li>
<li>cors在浏览器中有兼容性。只有支持XMLhttpRequst Level2的浏览器才可正常使用。</li>
</ol>
<h2 id="-">身份认证</h2>
<ol>
<li><strong>服务器端渲染</strong>推荐使用<strong>Session</strong>认证机制</li>
<li><strong>前后端分离</strong>推荐使用<strong>JWT</strong>认证机制</li>
</ol>
<h3 id="jwt-">jwt跨域身份认证</h3>
<h4 id="-">定义</h4>
<p>JWI (JSON Web Token) 目前最流行的<strong>跨域身份认证解决方案</strong></p>
<h4 id="-">原理</h4>
<p><img src="http://qi.zengzeng.pro/vscode/20230225172050.png" alt="jwt工作原理"></p>
<p>用户访问服务器后，服务器根据相关信息生成一个Token，发送给客户端，客户端存储到本地，在客户端再次访问服务器时，发送token，服务器再解密出token中的信息</p>
<h4 id="jwt-">JWT的<strong>组成部分</strong></h4>
<p>jwt通常由三部分组成，分别是Header（头部），Payload（有效荷载），Signature（签名）。中间以.分隔</p>
<ul>
<li>Payload 部分才是真正的用户信息，它是用户信息经过加密之后生成的字符串</li>
<li>Header 和Signature是安全性相关的部分，只是为了保证Token的安全性。</li>
</ul>
<p><img src="http://qi.zengzeng.pro/vscode/20230225173550.png" alt="20230225173550"></p>
<h4 id="-">使用方式</h4>
<p>客户端收到服务器返回的JWT之后通常会将它存储在<strong>localStorage</strong>或者<strong>sessionStorage</strong>中。  </p>
<p>此后，客户端每次与服务器通信都要带上这个JWT的字符串，从而进行身份认证。推荐的做法是把JWT放在HTTP请求头的Authorization字段中，格式如下：</p>
<pre><code>Authorization:Bearer &lt;token&gt;
</code></pre><h4 id="-">两个相关的包</h4>
<ul>
<li>jsonwebtoken 用于生成jwt字符串</li>
<li>epress-jwt 用户将jwt字符串解析还原成JSON对象</li>
</ul>
<h2 id="-express-jwt">在express中使用jwt</h2>
<p>为了<strong>保证JWT字符串的安全性</strong>，防止JWT在网路传输过程中被别人破解，我们需要专门定义一个用于<strong>加密</strong>和<strong>解密</strong>的secret密钥  </p>
<ol>
<li>在生成JWT字符串时需要根据secret加密</li>
<li>在解析JWT字符串时需要根据secret解密</li>
</ol>
<h3 id="sign-">sign方法</h3>
<p>返回一个加密的字符串
三个参数：</p>
<ol>
<li>用户的信息对象</li>
<li>加密的密钥</li>
<li>配置对象，配置当前有效期 expiresIn</li>
</ol>
<h3 id="express-jwt">express-jwt</h3>

          	</article>
        </div>
		</div>
  </body>
</html>
<script type="text/javascript" src="toc/js/jquery-1.4.4.min.js"></script>
<script type="text/javascript" src="toc/js/jquery.ztree.all-3.5.min.js"></script>
<script type="text/javascript" src="toc/js/ztree_toc.js"></script>
<script type="text/javascript" src="toc_conf.js"></script>

<SCRIPT type="text/javascript" >
<!--
$(document).ready(function(){
    var css_conf = eval(markdown_panel_style);
    $('#readme').css(css_conf)
    
    var conf = eval(jquery_ztree_toc_opts);
		$('#tree').ztree_toc(conf);
});
//-->
</SCRIPT>